#ifndef OCK_MEMORY_BRIDGE_OCK_ADAPTER_TASK_OCK_ASYNC_TASK_EXT_H
#define OCK_MEMORY_BRIDGE_OCK_ADAPTER_TASK_OCK_ASYNC_TASK_EXT_H
#include <memory>
#include "ock/acladapter/executor/OckAsyncTaskBase.h"
#include "ock/acladapter/executor/OckAsyncResultInnerBridge.h"

namespace ock {
namespace acladapter {

template<typename _ParamT, typename _ResultT>
class OckTaskFunOp
{
public:
    virtual ~OckTaskFunOp() noexcept = default;
    virtual OckTaskResourceType ResourceType(void) const = 0;
    virtual bool PreConditionMet(void) = 0;
    virtual std::shared_ptr<_ResultT> Run(
        OckAsyncTaskContext &context, _ParamT &param, OckUserWaitInfoBase &waitInfo);
};

template<typename _ParamT, typename _ResultT, typename _FunOpT>
class OckAsyncTaskExt : public OckAsyncTaskBase
{
public:
    typedef _ParamT ParamT;
    typedef _ResultT ResultT;
    typedef _FunOpT FunOpT;
    typedef OckAsyncResultInnerBridge<_ResultT> BridgeT;
    virtual ~OckAsyncTaskExt() noexcept = default;
    explicit OckAsyncTaskExt(std::shared_ptr<_ParamT> &param,
        std::shared_ptr<OckAsyncResultInnerBridge<_ParamT>> &bridge, std::shared_ptr<OckTaskConditionWaitBase> &waiter,
        std::shared_ptr<_FunOpT> &funOp);

    std::string Name(void) const override;
    std::string ParamInfo(void) const override;

    OckTaskResourceType ResourceType(void) const override;
    bool PreConditionMet(void) override;
    void Run(OckAsyncTaskContext &context) override;
    void Cancel(void) override;

    static std::shared_ptr<OckAsyncTaskBase> Create(std::shared_ptr<_ParamT> param,
            std::shared_ptr<OckAsyncResultInnerBridge<_ParamT>> bridge,
            std::shared_ptr<OckTaskConditionWaitBase> waiter = std::shared_ptr<OckTaskConditionWaitBase>(nullptr))
    {
        return std::shared_ptr<OckAsyncTaskBase>(
            new OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>(param, bridge, waiter, std::make_pair<_FunOpT>()));
    }

    static std::shared_ptr<OckAsyncTaskBase> Create(std::shared_ptr<_ParamT> param, std::shared_ptr<_FunOpT> funOp
            std::shared_ptr<OckAsyncResultInnerBridge<_ParamT>> bridge,
            std::shared_ptr<OckTaskConditionWaitBase> waiter = std::shared_ptr<OckTaskConditionWaitBase>(nullptr))
    {
        return std::shared_ptr<OckAsyncTaskBase>(
            new OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>(param, bridge, waiter, funOp));
    }

private:
    std::shared_ptr<_ParamT> param;
    std::shared_ptr<OckAsyncResultInnerBridge<_ParamT>> bridge;
    std::shared_ptr<OckTaskConditionWaitBase> waiter;
    std::shared_ptr<_FunOpT> funOp;
};

using OckDftTaskFunOp = OckTaskFunOp<OckDftAsyncTaskParam, OckDefaultResult>;
template<typename _ParamT, typename _ResultT, typename _FunOpT>
OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>::OckAsyncTaskExt(std::shared_ptr<_ParamT> &param,
        std::shared_ptr<OckAsyncResultInnerBridge<_ParamT>> &bridge, std::shared_ptr<OckTaskConditionWaitBase> &waiter,
        std::shared_ptr<_FunOpT> &funOp)
        : param(param), bridge(bridge), waiter(waiter), funOp(funOp)
{}

template<typename _ParamT, typename _ResultT, typename _FunOpT>
std::string OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>::Name(void) const
{
    return typeid(_FunOpT).name();
}

template<typename _ParamT, typename _ResultT, typename _FunOpT>
std::string OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>::ParamInfo(void) const
{
    std::ostringstream osStr;
    osStr << *param;
    return osStr.str();
}

template<typename _ParamT, typename _ResultT, typename _FunOpT>
std::string OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>::PreConditionMet(void) const
{
    return funOp->PreConditionMet();
}

template<typename _ParamT, typename _ResultT, typename _FunOpT>
std::string OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>::ResourceType(void) const
{
    return funOp->ResourceType();
}

template<typename _ParamT, typename _ResultT, typename _FunOpT>
std::string OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>::Run(OckAsyncTaskContext) const
{
    if (waiter.get() != nullptr) {
        waiter->Wait();
    }
    if (bridge->WaitTimeOut) {
        return;
    }
    bridge->SetResult(funOp->Run(context, *param, *bridge));
    
}

template<typename _ParamT, typename _ResultT, typename _FunOpT>
std::string OckAsyncTaskExt<_ParamT, _ResultT, _FunOpT>::Cancel(void) 
{
    return funOp->Cancel();
}
}
}
#endif